Fix erlang:raise/3 assert with built stacktrace#2252
Fix erlang:raise/3 assert with built stacktrace#2252bettio wants to merge 1 commit intoatomvm:release-0.7from
Conversation
07263bb to
7e62129
Compare
7e62129 to
86ff1db
Compare
| term_put_tuple_element(stack_info, 2, term_from_int(0)); | ||
| term_put_tuple_element(stack_info, 3, term_from_int(0)); | ||
| term_put_tuple_element(stack_info, 4, built_stacktrace); | ||
| term_put_tuple_element(stack_info, 5, exception_class); |
Check failure
Code scanning / CodeQL
Use of term variable after garbage collection Error
86ff1db to
949690a
Compare
|
https://ampcode.com/threads/T-019d4d69-3ac6-718e-8d7c-1ad32f287c7b PR Review: Fix erlang:raise/3 assert with built stacktraceCommit: SummaryWhen The fix:
Verdict: ✅ Approve with suggestionsThe core fix is correct and well-reasoned for the interpreter path. GC root handling is safe, Issues Found🔴 Critical: JIT
|
When erlang:raise/3 is called with a built stacktrace (list of
{M,F,A,Loc} tuples) and the re-raised exception passes through a
try/catch whose clauses do not match, the compiler-generated catch-all
(OP_RAISE) calls stacktrace_exception_class, which asserts on a
6-tuple. The built list was stored as-is, never wrapped.
Wrap the built stacktrace into a raw 6-tuple in stacktrace_create_raw_mfa
so OP_RAISE and stacktrace_build can process it. Route OP_RAW_RAISE
through HANDLE_ERROR() so it also hits the wrapping path.
Use term_invalid_term() instead of term_nil() as the
exception_stacktrace sentinel so that an empty stacktrace [] passed to
erlang:raise/3 is correctly detected and preserved, matching OTP
behavior.
Signed-off-by: Davide Bettio <davide@uninstall.it>
949690a to
b76f2c3
Compare
I think I fixed all of them. |
|
looks good, this is suggested for the codeql complaining, no strong preference on my part.. CodeQL Fix: Use-after-GC false positive in stacktrace.cCodeQL flagged term stacktrace_create_raw_mfa(Context *ctx, Module *mod, int current_offset, term module_atom, term function_atom, int arity)
{
- term exception_class = context_exception_class(ctx);
-
if (term_is_list(ctx->exception_stacktrace)) {
// Already a built stacktrace (possibly empty) from erlang:raise/3
...
term_put_tuple_element(stack_info, 4, built_stacktrace);
- // NOLINT(term-use-after-gc) exception_class is always an atom
- term_put_tuple_element(stack_info, 5, exception_class);
+ term_put_tuple_element(stack_info, 5, context_exception_class(ctx));
return stack_info;
}
...
ctx->x[live_x_regs - 1] = ctx->exception_reason;
- // NOLINT(term-use-after-gc) exception_class is always an atom
if (UNLIKELY(memory_ensure_free_with_roots(ctx, requested_size, live_x_regs, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
...
...
term_put_tuple_element(stack_info, 4, raw_stacktrace);
- term_put_tuple_element(stack_info, 5, exception_class);
+ term_put_tuple_element(stack_info, 5, context_exception_class(ctx));
return stack_info;
}No behavioral change — |
stacktrace_exception_classwhenerlang:raise/3is called with a built stacktrace and the re-raised exception hits a non-matching catch clause (triggering the compiler-generatedOP_RAISE)stacktrace_create_raw_mfaOP_RAW_RAISEthroughHANDLE_ERROR()so both the NIF path and theraw_raiseopcode path go through the wrapping logicstacktrace_buildfor pre-built stacktracesFixes #2185
These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later